% -*- coding: utf-8 -*-
% Ada 95 品质和风格
% 版权所有 (C) 2009,2010,2011 朱群英
% Copyright (C) 2009,2010,2011 Zhu Qun-Ying
%
% 本书的 TeX 代码和由之生成的 ps，pdf，html，等其他格式的文件
% 遵循 GNU通用公共授权第三版或其后的版本。
%
% 本书是基于有益的目的而加以发布，然而不负任何担保责任。
%
% 您应已收到附随于本书的GNU通用公共授权的副本；如果没有，
% 请参考 <http://www.gnu.org/licenses/gpl.html>

\section{使用类型}

强类型促进软件的可靠性。一个对象的类型定义了所有合法的值和操作，
这允许编译器在编译时检验和识别潜在的错误。
另外，类型的规则允许编译器生成在执行时
检验违反类型约束的代码。运用这些 Ada 编译器的特性，比其他没那么强
类型的语言更早以及更完整的检测出错误。

\subsection{类型声明准则}
\glentry{准则}
\begin{itemize}
    \item 尽量限制标量类型的值域。
    \item 从应用中查找可能值的信息。
    \item 不要重用标准 (Standard) 包中的子类型名称。
    \item 用子类型声明来促进程序的可读性 (\cite{booch87})。
    \item 协调使用导出类型和子类型 (\ref{c:prog-prac:types:derived})。
\end{itemize}

\glentry{范例}
\begin{blockindent}
\begin{lstlisting}
subtype Card_Image is String (1 .. 80);
Input_Line : Card_Image := (others => ' ');
-- restricted integer type:
type    Day_Of_Leap_Year     is                  range 1 .. 366;
subtype Day_Of_Non_Leap_Year is Day_Of_Leap_Year range 1 .. 365;
\end{lstlisting}

下面的声明，程序员的意思是:``我不知道有多少。'' 但是实际的基本值域会
掩埋在代码中或作为系统参数：

\begin{lstlisting}
Employee_Count : Integer;
\end{lstlisting}
\end{blockindent}

\glentry{原理}
\begin{blockindent}
把无意义的数值从合法的范围内剔除，增加了编译器检测到错误的能力。
这也提高了程序的可读性。另外，当对象声明为这些子类型时，
这也让你仔细考虑每次对象的使用。

不同的实现对于大多数预定义类型提供了不同的一套数值。读者不能从预定义
的名字知道预期的值域。当预定义名字被重载这样的情形会更恶化。

对象和子类型的名字可以阐明他们预期的使用和作为底层设计决定的文档。
上面的范例中，记录了限制软件的设计决定：只能用在物理参数符合穿孔卡
特性的设备。这些信息很容易找到，因此提高了程序的可维护性。

可以通过声明一个没有限制的子类型来实现类型的重命名 (\cite{arm95} \S{}8.5)。
子类型的名字不可以被重载; 重载只能用在客调用的实体。
枚举的实字被当作无参数的函数，所以包含在这个规则里。

类型可以是有高度约束的一组值，同时没有排除掉有用的值。
在\ref{c:prog-prac:types:derived}中描述的用法在执行语句中排除了许多标志变量和
类型转换。这令程序更易读，同时也允许编译器强化强类型约束。
\end{blockindent}

\glentry{注解}
\begin{blockindent}
子类型声明没有定义一新类型，只是在现有的类型上加了限制。

任何与本准则的偏差，都会导致对 Ada 语言中强类型机制的损伤。
\end{blockindent}


\glentry{异例}
\begin{blockindent}
有些情况下，你并不需要依赖某个特定的数值范围。这些情况确实存在，例如
数组的索引(如一个列表的大小没有任何语义上的限制)。参见准则
\ref{c:portability:num-type:pre-def-num-type} 有关正确使用预定义类型的讨论。
\end{blockindent}

\subsection{枚举类型}
\glentry{准则}
\begin{itemize}
\item 用枚举类型替代数字码。
\item 只有在绝对必要的时候，才用表示语句来匹配外部设备的需求。
\end{itemize}

\glentry{范例}
\begin{blockindent}
用:
\begin{lstlisting}
type Color is (Blue, Red, Green, Yellow);
\end{lstlisting}
来代替:
\begin{lstlisting}
Blue   : constant := 1;
Red    : constant := 2;
Green  : constant := 3;
Yellow : constant := 4;
\end{lstlisting}
如果学要才加入以下的内容:
\begin{lstlisting}
for Color use (Blue   => 1,
               Red    => 2,
               Green  => 3,
               Yellow => 4);
\end{lstlisting}
\end{blockindent}

\glentry{原理}
\begin{blockindent}
枚举比数字码更健壮。在遇到不正确的解释或在维护中增加或删除数值的时候，
因此而引起的潜在错误会少。数字码是从那些没有用户类型定义的语言
遗留下来的。

另外，Ada 提供了一系列属性操作给枚举类型 (\texttt{'}Pos, \texttt{'}Val,
\texttt{'}Succ, \texttt{'}Pred, \texttt{'}Image 和 \texttt{'}Value)，
用起来比用户自己写的编码操作更可靠。

一开始的时候，数字码也许看起来适合用在匹配外部数值。这种情况就需要
枚举类型的表示语句。表示语句记录了``编码''。如果程序结构能正确分隔和
封装硬件依赖(参见准则\cite{c:portability:fundamental:encapsulating}),
数字代码就会封装在接口包中，如果要求改变了，这很容易被找到和取代。

通常，尽量避免使用枚举类型的表示语句。当枚举文字没有明显的排列顺序，
枚举的表示语句可能会引起移植性问题。例如由于新平台的表示顺序的改变，
枚举的顺序必须跟着改变。
\end{blockindent}
